home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 January: Mac OS SDK / Dev.CD Jan 98 SDK2.toast / Development Kits (Disc 2) / QuickDraw GX / Programming Stuff / GX Libraries / LayoutEditLibrary.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-27  |  37.1 KB  |  1,754 lines  |  [TEXT/MPS ]

  1.  
  2. /*
  3.     File:        LayoutEditLibrary.c
  4.  
  5.     Contains:    graphics libraries - simple layout editing based on the TextEdit model
  6.  
  7.     Written by:    Dave Opstad, Eric Mader
  8.  
  9.     Copyright:    © 1995 by Apple Computer, Inc., all rights reserved.
  10.  
  11.     Change History (most recent first):
  12.  
  13.          <6>     6/26/95    TD        fixing up protos
  14.          <5>      5/4/95    JD        updating GetEnvirons to GetScriptManagerVariable (yup, I get
  15.                                     paid for this…)
  16.          <4>      4/7/95    jtd        removing unused variables from routines
  17.          <3>     1/24/95    JD        updated to latest GX 1.1 source (as of 16 Jan 1995)
  18.          <2>      1/9/95    JD        changed 'boolean' to 'Boolean'
  19.          <1>      1/9/95    JD        First checked in.
  20. */
  21.  
  22. #include <Types.h>
  23. #include <Memory.h>
  24. #include <Events.h>
  25. #include <OSUtils.h>
  26. #include <Scrap.h>
  27. #include <Script.h>
  28. #include <GXTypes.h>
  29. #include <GXLayout.h>
  30. #include <GXGraphics.h>
  31. #include <GXEnvironment.h>
  32. #include "SelectionLibrary.h"
  33. #include "GraphicsLibraries.h"
  34. #include "StorageLibrary.h"
  35. #include "LayoutEditLibrary.h"
  36.  
  37.  
  38. #define LockHandle(handle) (HLock ((Handle)handle), *handle)
  39. #define UnlockHandle(handle) HUnlock ((Handle)handle)
  40.  
  41. #define LockEditHandle(handle) (LayoutEditPtr) LockHandle(handle)
  42. #define UnlockEditHandle(handle) UnlockHandle(handle)
  43.  
  44. #define MIN(a,b) ((a) < (b)? (a): (b))
  45. #define MAX(a,b) ((a) > (b)? (a): (b))
  46.  
  47. #define maxRanges 10
  48. #define textBufferLength 16
  49. #define nextUpdateDelta 5
  50.  
  51. #define layoutOutOfDate 0x8000
  52. #define highlightOutOfDate 0x4000
  53. #define highlightBlinks 0x2000
  54. #define highlightIsBlinking 0x1000
  55.  
  56. #define BOUNDS 0
  57.  
  58. enum
  59. {
  60.     backSpace = 8,
  61.     leftArrow = 0x1C,
  62.     rightArrow,
  63.     upArrow,
  64.     downArrow
  65. };
  66.  
  67. typedef unsigned long ulong;
  68. typedef unsigned short ushort;
  69.  
  70. /*
  71.     The LayoutEditRecord contains the layout and highlight shapes,
  72.     the selection. flags contains flags which indicate that the
  73.     layout and highlight shapes haven't been rebuilt since their
  74.     corresponding data in the LayoutEditRecord has been changed.
  75.     
  76.     nextUpdate time, if non-zero tells the idle routine when to
  77.     update and re-draw the layout gxShape. 
  78.     
  79.     selectionRanges is working storage used for manipulating the
  80.     layout's selection. NOTE: the actual handle containing the
  81.     LayoutEditRecord will be large enough to contain the
  82.     SelectionOffsetRange array which immediately follows selectionRanges.
  83. */
  84. typedef struct {
  85.     short flags;
  86.     short highlightHideCount;
  87.     short    oldScript;
  88.     SelectionOffset synchOffset;
  89.     gxShape layout;
  90.     gxShape eraser;
  91.     gxShape highlight;
  92.  
  93. #if BOUNDS
  94.     gxShape bounds;
  95.     gxShape boundsEraser;
  96. #endif
  97.  
  98.     SelectionHandle selection;
  99.     gxShape scrap;
  100.     ulong nextUpdateTime;
  101.     ulong nextBlinkTime;
  102.     long deleteStartOffset;
  103.     long deleteEndOffset;
  104.     gxStyle insertionStyle;
  105.     short insertionLevel;
  106.     short textBufferOffset;
  107.     char textBuffer[textBufferLength];
  108.     SelectionRanges selectionRanges;
  109. } LayoutEditRecord, *LayoutEditPtr;
  110.  
  111.  
  112. /*
  113.     I N T E R N A L   R O U T I N E S
  114. */
  115.  
  116.  
  117. /*
  118.     Draw the part of the layout which has changed.
  119. */
  120. static void DrawDifference(LayoutEditPtr layout)
  121. {
  122.     GXDrawShape(layout->eraser);
  123.  
  124. #if BOUNDS
  125.     GXDrawShape(layout->boundsEraser);
  126. #endif
  127.  
  128.     GXDrawShape(layout->layout);
  129.  
  130. #if BOUNDS
  131.     GXDrawShape(layout->bounds);
  132. #endif
  133. }
  134.  
  135. /*
  136.     Synch the keyboard to the font at the new selection.
  137. */
  138. static void SynchKeyboard(LayoutEditPtr layout)
  139. {
  140.     long styleRuns;
  141.     gxStyle selectionStyle;
  142.     gxFontPlatform platform;
  143.     gxFontScript script;
  144.     gxFontLanguage language;
  145.  
  146.     GXGetLayoutParts(
  147.         layout->layout,
  148.         layout->synchOffset, layout->synchOffset,
  149.         nil,
  150.         &styleRuns, nil, &selectionStyle,
  151.         nil, nil, nil);
  152.     
  153.     if (styleRuns == 0 || selectionStyle == nil)
  154.         selectionStyle = GXGetShapeStyle(layout->layout);
  155.         
  156.     platform = GXGetStyleEncoding(selectionStyle, &script, &language);
  157.     
  158.     switch (platform)
  159.     {
  160.         case gxUnicodePlatform:
  161.             break;
  162.         
  163.         case gxMacintoshPlatform:
  164.             if (script == gxNoScript)
  165.                 script = smRoman;
  166.             else
  167.                 script -= 1;
  168.  
  169.             if (language != gxNoLanguage && GetScriptVariable((short) script, smScriptLang) != language - 1)
  170.                 SetScriptVariable((short) script, smScriptLang, language - 1);
  171.             
  172.             if (GetScriptManagerVariable(smKeyScript) != script)    
  173.                 KeyScript((short) script);
  174.             break;
  175.             
  176.         default:
  177.             break;
  178.     }
  179. }
  180.  
  181. /*
  182.     Make sure the caret is not blinked out.
  183. */
  184. static void ResetCaret(LayoutEditPtr layout)
  185. {
  186.     layout->nextBlinkTime = TickCount() + GetCaretTime();
  187.     if ((layout->flags & highlightBlinks) && (layout->flags & highlightIsBlinking))
  188.     {
  189.         layout->flags ^= highlightIsBlinking;
  190.         if (--layout->highlightHideCount == 0)
  191.             GXDrawShape(layout->highlight);
  192.     }
  193. }
  194.  
  195. /*
  196.     Build a selection from start to end. If start and end are equal,
  197.     the selection will be a caret.
  198. */
  199. static void NewSelection(LayoutEditPtr layout, SelectionOffset start, SelectionOffset end)
  200. {
  201.     layout->selectionRanges.rangeCount = 1;
  202.     layout->selectionRanges.ranges[0].minOffset = start;
  203.     layout->selectionRanges.ranges[0].maxOffset = end;
  204.     
  205.     if (layout->selection)
  206.         DisposeSelection(layout->selection);
  207.         
  208.     layout->selection = NewRangeSelection(&layout->selectionRanges.ranges[0]);
  209.     
  210.     layout->synchOffset = start;
  211.     layout->flags |= highlightOutOfDate;
  212. }
  213.  
  214. /*
  215.     Update the layout's highlight gxShape if the selection's
  216.     changed since we last built it.
  217. */
  218. static void UpdateHighlight(LayoutEditPtr layout)
  219. {
  220.     if (layout->flags & highlightOutOfDate)
  221.     {
  222.         DisposeShapeAt(&layout->highlight);
  223.         
  224.         layout->highlight = GetLayoutSelection(
  225.             layout->layout,
  226.             layout->selection,
  227.             0,
  228.             gxHighlightAverageAngle,
  229.             gxSplitCaretType);
  230.  
  231.         if (GetSelectionType(layout->selection) == simpleCaret)
  232.         {
  233.             SetShapeFastXorTransfer(layout->highlight, nil, nil);
  234.             layout->flags |= highlightBlinks;
  235.         }
  236.         else
  237.         {
  238.             SetShapeCommonTransfer(layout->highlight, gxHighlightMode);
  239.             SetShapeCommonColor(layout->highlight, gxWhite);
  240.             
  241.             layout->flags &= ~highlightBlinks;
  242.             if (layout->flags & highlightIsBlinking)
  243.             {
  244.                 layout->flags ^= highlightIsBlinking;
  245.                 --layout->highlightHideCount;
  246.             }
  247.         }
  248.             
  249.         DisposeStyleAt(&layout->insertionStyle);
  250.         layout->insertionLevel = -1;
  251.  
  252.         SynchKeyboard(layout);
  253.         layout->flags &= ~highlightOutOfDate;
  254.     }
  255. }
  256.  
  257. /*
  258.     Build a new selection from start to end, and a new highlight gxShape
  259.     that matches it.
  260. */
  261. static void NewSelectionAndHighlight(
  262.     LayoutEditPtr layout,
  263.     SelectionOffset start,
  264.     SelectionOffset end)
  265. {
  266.     NewSelection(layout, start, end);
  267.     UpdateHighlight(layout);
  268. }
  269.  
  270. /*
  271.     Return the offset of the glyph before the one at the specified
  272.     offset in the layout's text.
  273. */
  274. static SelectionOffset GetPreviousOffset(gxShape layout, SelectionOffset offset)
  275. {
  276.     ushort firstGlyph, secondGlyph;
  277.     gxLayoutOffsetState offsetState;
  278.     static SelectionOffset offsetStateSizes[] = {1, 1, 2, 2, 0};
  279.     
  280.     GXGetOffsetGlyphs(layout, offset, 0, &offsetState, &firstGlyph, &secondGlyph);
  281.     
  282.     return offset - offsetStateSizes[offsetState & ~gxOffsetInsideLigature];
  283. }
  284.  
  285. /*
  286.     Delete the text from the layout in the range specified by pRange.
  287. */
  288. static void DeleteRange(LayoutEditPtr layout, SelectionOffsetRange *pRange)
  289. {
  290.     if (layout->deleteStartOffset < 0)
  291.         layout->deleteEndOffset = pRange->maxOffset;
  292.         
  293.     layout->deleteStartOffset = pRange->minOffset;
  294.     layout->flags |= layoutOutOfDate;
  295. }
  296.  
  297.  
  298. /*
  299.     Delete the selected text from the layout. If the selection is a
  300.     caret, delete the character before the caret. Change the selection
  301.     to a caret just before the old selection.
  302. */
  303.  
  304. static void DeleteSelection(LayoutEditPtr layout)
  305. {
  306.     SelectionType selectionType = GetSelectionType(layout->selection);
  307.     SelectionOffset newCaret;
  308.  
  309.     switch (selectionType)
  310.     {    
  311.     case emptySelection:
  312.         newCaret = 0;
  313.         break;
  314.     
  315.     case simpleCaret:
  316.     {
  317.         SelectionOffset caret = GetCaretSelection(layout->selection, nil);
  318.     
  319.         if(layout->textBufferOffset)
  320.         {
  321.             layout->textBufferOffset -= 1;
  322.             newCaret = caret - 1;
  323.         }
  324.         else if (caret > 0)
  325.         {
  326.             SelectionOffsetRange range;
  327.             SelectionOffset previous = GetPreviousOffset(layout->layout, caret);
  328.         
  329.             range.minOffset = newCaret = previous;
  330.             range.maxOffset = caret;
  331.             DeleteRange(layout, &range);
  332.         }
  333.         else newCaret = caret;
  334.         
  335.     break;
  336.     }
  337.     
  338.     case simpleRange:
  339.     case discontiguousRange:
  340.     {
  341.         long rangeCount;
  342.         SelectionRanges *ranges = &layout->selectionRanges;
  343.         SelectionOffsetRange *pRange;
  344.         
  345.         (void) GetRangeSelection(layout->selection, ranges);
  346.         rangeCount = ranges->rangeCount;
  347.         pRange = &ranges->ranges[rangeCount];
  348.         
  349.         /*
  350.             go through the ranges backwards to save sliding stuff
  351.             that'll get deleted later and so that the caret is set
  352.             for the first range.
  353.         */
  354.         while (--rangeCount >= 0)
  355.         {
  356.             DeleteRange(layout, --pRange);
  357.             newCaret = pRange->minOffset;
  358.         }
  359.             
  360.         break;
  361.     }
  362.         
  363.     }
  364.     
  365.     /* set layout's selection to a caret before the deletion */
  366.     NewSelection(layout, newCaret, newCaret);
  367.     ResetCaret(layout);
  368. }
  369.  
  370. /*
  371.     Make sure the handle is at least newSize bytes long;
  372.     If it isn't, grow it to be newSize + extra.
  373. */
  374. static Ptr GrowAndLockHandle(Handle handle, Size newSize, Size extra)
  375. {
  376.     Size oldSize = GetHandleSize(handle);
  377.  
  378.     if (oldSize < newSize)
  379.         SetHandleSize(handle, newSize + extra);
  380.         
  381.     return LockHandle(handle);
  382. }
  383.  
  384. #if BOUNDS
  385. static void SetBounds(LayoutEditPtr layout)
  386. {
  387.     gxRectangle bounds;
  388.     
  389.     GXGetShapeTypographicBounds(layout->layout, &bounds);
  390.     GXSetRectangle(layout->bounds, &bounds);
  391.     GXIgnoreGraphicsNotice(transform_already_set);
  392.     GXSetShapeTransform(layout->bounds, GXGetShapeTransform(layout->layout));
  393.     GXPopGraphicsNotice();
  394. }
  395. #endif
  396.  
  397. static void SetEraser(LayoutEditPtr layout)
  398. {
  399.     layout->eraser = GXCopyToShape(layout->eraser, layout->layout);
  400.     SetShapeCommonColor(layout->eraser, gxWhite);
  401.  
  402. #if BOUNDS    
  403.     layout->boundsEraser = GXCopyToShape(layout->boundsEraser, layout->bounds);
  404.     SetShapeCommonColor(layout->boundsEraser, gxWhite);
  405. #endif
  406. }
  407.  
  408. /*
  409.     If the backing store in the LayoutEditRecord has changed since
  410.     the layout gxShape was last built, rebuild the layout.
  411. */
  412. static void UpdateLayout(LayoutEditPtr layout)
  413. {
  414.     if (layout->flags & layoutOutOfDate)
  415.     {
  416.         void *textBuffer = &layout->textBuffer, **text = nil;
  417.         short *levels = nil, levelRunCount = 0, styleRunCount = 0, textRunCount = 0,
  418.                     *textRunLength = nil, *styleRunLength = nil, *levelRunLength = nil;
  419.         gxStyle *styles = nil;
  420.         
  421.         SetEraser(layout);
  422.         
  423.         if (layout->textBufferOffset)
  424.         {
  425.             text = &textBuffer;
  426.             textRunLength = &layout->textBufferOffset;
  427.             textRunCount = 1;
  428.             
  429.             if (layout->insertionStyle)
  430.             {
  431.                 styles = &layout->insertionStyle;
  432.                 styleRunLength = textRunLength;
  433.                 styleRunCount = 1;
  434.             }
  435.             
  436.             if (layout->insertionLevel >= 0)
  437.             {
  438.                 levels = &layout->insertionLevel;
  439.                 levelRunLength = textRunLength;
  440.                 levelRunCount = 1;
  441.             }
  442.         }
  443.         
  444.         /* edit the layout */ 
  445.         GXSetLayoutParts(
  446.             layout->layout,
  447.             layout->deleteStartOffset,
  448.             layout->deleteEndOffset,
  449.             textRunCount,
  450.             textRunLength,
  451.             (const void **) text,
  452.             styleRunCount,
  453.             styleRunLength,
  454.             styles,
  455.             levelRunCount,
  456.             levelRunLength,
  457.             levels);
  458.         
  459. #if BOUNDS        
  460.         SetBounds(layout);
  461. #endif
  462.             
  463.         /* erase the old layout and draw the new one */
  464.         DrawDifference(layout);
  465.  
  466.         layout->flags &= ~layoutOutOfDate;
  467.         layout->nextUpdateTime = 0;
  468.         layout->textBufferOffset = 0;
  469.         layout->deleteStartOffset = -1;
  470.         layout->insertionLevel = -1;
  471.         DisposeStyleAt(&layout->insertionStyle);
  472.     }
  473. }
  474.  
  475. /*
  476.     Add a character to the layout at the selection. This routine
  477.     assumes that the selection is a caret; i.e. if it was a range,
  478.     the range has been deleted leaving a caret.
  479. */
  480. static void InsertByte(LayoutEditPtr layout, char byte)
  481. {
  482.     SelectionOffset caret;
  483.  
  484.     caret = layout->selectionRanges.ranges[0].minOffset;
  485.     
  486.     if (layout->textBufferOffset >= textBufferLength)
  487.         UpdateLayout(layout);
  488.     
  489.     if (layout->deleteStartOffset < 0)
  490.         layout->deleteStartOffset = layout->deleteEndOffset = caret;
  491.         
  492.     layout->textBuffer[layout->textBufferOffset++] = byte;
  493.     
  494.     /* set selection to a caret after the new byte */
  495.     NewSelection(layout, caret + 1, caret + 1);
  496.     ResetCaret(layout);
  497.     
  498.     layout->flags |= layoutOutOfDate;
  499. }
  500.  
  501. /*
  502.     If the highlight gxShape isn't already hidden, erase
  503.     it by drawing it on top of itself.
  504. */
  505. static void HideHighlight(LayoutEditPtr layout)
  506. {
  507.     if (layout->highlightHideCount++ == 0)
  508.         GXDrawShape(layout->highlight);
  509. }
  510.  
  511. /*
  512.     If the highlight gxShape isn't already visible, update it
  513.     and draw it.
  514. */
  515. static void ShowHighlight(LayoutEditPtr layout)
  516. {
  517.     if (--layout->highlightHideCount <= 0)
  518.     {
  519.         UpdateHighlight(layout);
  520.         GXDrawShape(layout->highlight);
  521.         layout->highlightHideCount = 0;
  522.     }
  523. }
  524.  
  525. /*
  526.     Draw the highlight shape (if it's visible).
  527. */
  528. static void DrawHighlight(LayoutEditPtr layout)
  529. {
  530.     if (layout->highlightHideCount <= 0)
  531.         GXDrawShape(layout->highlight);
  532. }
  533.  
  534. static void DrawChangedLayout(LayoutEditPtr layout)
  535. {
  536.     HideHighlight(layout);
  537.  
  538. #if BOUNDS    
  539.     SetBounds(layout);
  540. #endif
  541.         
  542.     DrawDifference(layout);
  543.     
  544.     layout->flags |= highlightOutOfDate;
  545.     ShowHighlight(layout);
  546. }
  547.  
  548. static void CopySelection(LayoutEditPtr layout)
  549. {
  550.     SelectionType selectionType = GetSelectionType(layout->selection);
  551.  
  552.     switch (selectionType)
  553.     {
  554.     case emptySelection:
  555.     case simpleCaret:
  556.     case discontiguousRange:
  557.         break;
  558.     
  559.     case simpleRange:
  560.     {
  561.         SelectionRanges *ranges = &layout->selectionRanges;
  562.         SelectionOffsetRange *pRange;
  563.         
  564.         (void) GetRangeSelection(layout->selection, ranges);
  565.         pRange = ranges->ranges;
  566.  
  567.         layout->scrap = GXGetLayoutShapeParts(layout->layout, pRange->minOffset, pRange->maxOffset, layout->scrap);                
  568.  
  569.         break;
  570.     }
  571.     }
  572. }
  573.  
  574. static void PasteSelection(LayoutEditPtr layout)
  575. {
  576.     SelectionType selectionType = GetSelectionType(layout->selection);
  577.     SelectionOffset newCaret, startOffset, endOffset;
  578.     
  579.     SetEraser(layout);
  580.  
  581.     switch (selectionType)
  582.     {
  583.     case emptySelection:
  584.     case discontiguousRange:
  585.         return;
  586.  
  587.     case simpleCaret:
  588.         newCaret = startOffset = endOffset = GetCaretSelection(layout->selection, nil);
  589.         break;
  590.     
  591.     case simpleRange:
  592.     {
  593.         SelectionRanges *ranges = &layout->selectionRanges;
  594.         
  595.         (void) GetRangeSelection(layout->selection, ranges);
  596.         startOffset = ranges->ranges[0].minOffset;
  597.         endOffset = ranges->ranges[0].maxOffset;
  598.         newCaret = startOffset;
  599.         
  600.         
  601.         break;
  602.     }
  603.  
  604.     }
  605.     newCaret += GXGetLayout(layout->scrap, nil, 0, nil, nil, 0, nil, nil, nil, nil);
  606.     GXSetLayoutShapeParts(layout->layout, startOffset, endOffset, layout->scrap);
  607.  
  608. #if BOUNDS
  609.     SetBounds(layout);
  610. #endif
  611.  
  612.     DrawDifference(layout);
  613.     NewSelection(layout, newCaret, newCaret);
  614. }
  615.  
  616. static void AdjustSelectedLevels(LayoutEditPtr layout, short levelAdjust)
  617. {
  618.     short *lengths, *levels;
  619.     long levelRunCount;
  620.     SelectionType selectionType = GetSelectionType(layout->selection);
  621.     SelectionRanges *ranges = &layout->selectionRanges;
  622.     SelectionOffset startOffset, endOffset;
  623.     
  624.     UpdateLayout(layout);
  625.     
  626.     switch (selectionType)
  627.     {
  628.     case emptySelection:
  629.     case discontiguousRange:
  630.         return;
  631.         
  632.     case simpleCaret:
  633.         startOffset = endOffset = GetCaretSelection(layout->selection, nil);
  634.         break;
  635.     
  636.     case simpleRange:
  637.     {
  638.         SelectionRanges *ranges = &layout->selectionRanges;
  639.     
  640.         GetRangeSelection(layout->selection, ranges);
  641.         startOffset = ranges->ranges[0].minOffset;
  642.         endOffset = ranges->ranges[0].maxOffset;
  643.     }
  644.     break;
  645.     }
  646.     
  647.     GXGetLayoutParts(layout->layout, startOffset, endOffset, nil, nil, nil, nil, &levelRunCount, nil, nil);
  648.     
  649.     levels = (short *) NewPtr(levelRunCount * sizeof(short));
  650.     lengths = (short *) NewPtr(levelRunCount * sizeof(short));
  651.     
  652.     GXGetLayoutParts(layout->layout, startOffset, endOffset, nil, nil, nil, nil, nil, lengths, levels);
  653.     
  654.     if (startOffset == endOffset) layout->insertionLevel = MAX(*levels + levelAdjust, 0);
  655.     else
  656.     {
  657.         short i, length = endOffset - startOffset, *pl;
  658.     
  659.         SetEraser(layout);
  660.         
  661.         for (pl = levels, i = levelRunCount - 1; i >= 0; --i, ++pl)
  662.             *pl = MAX(*pl + levelAdjust, 0);
  663.  
  664.         
  665.         GXSetLayoutParts(
  666.             layout->layout,
  667.             startOffset,
  668.             endOffset,
  669.             0,
  670.             nil,
  671.             nil,
  672.             0,
  673.             nil,
  674.             nil,
  675.             levelRunCount,
  676.             lengths,
  677.             levels);
  678.             
  679.         HideHighlight(layout);
  680.  
  681.     #if BOUNDS
  682.         SetBounds(layout);
  683.     #endif
  684.  
  685.         DrawDifference(layout);
  686.         ShowHighlight(layout);
  687.         
  688.         layout->insertionLevel = -1;
  689.     }
  690.     
  691.     DisposePtr((Ptr) lengths);
  692.     DisposePtr((Ptr) levels);
  693. }
  694.  
  695.  
  696. /*
  697.     P U B L I C   R O U T I N E S
  698. */
  699.  
  700. LayoutEditHandle LayoutEditHandleFromLayout(gxShape layoutShape)
  701. {
  702.     LayoutEditHandle handle;
  703.     LayoutEditPtr layout;
  704. #if BOUNDS
  705.     gxRectangle bounds;
  706. #endif
  707.  
  708.     /* SetShapeFastXorTransfer(layoutShape, nil, nil); */
  709.     
  710.     handle = (LayoutEditHandle) NewHandle(
  711.         sizeof(LayoutEditRecord) + maxRanges * sizeof(SelectionOffsetRange));
  712.     
  713.     layout = LockEditHandle(handle);
  714.     layout->layout = layoutShape;
  715.     layout->eraser = nil;
  716.     layout->flags = 0;
  717.     layout->selection = nil;
  718.     layout->highlight = nil;
  719.     layout->scrap = nil;
  720.     layout->highlightHideCount = 0;
  721.     layout->nextUpdateTime = 0;
  722.     layout->nextBlinkTime = 0;
  723.     layout->textBufferOffset = 0;
  724.     layout->insertionStyle = nil;
  725.     layout->insertionLevel = -1;
  726.     layout->deleteStartOffset = -1;
  727.     
  728. #if BOUNDS    
  729.     layout->boundsEraser = nil;
  730.     GXGetShapeTypographicBounds(layoutShape, &bounds);
  731.     layout->bounds = GXNewRectangle(&bounds);
  732.     GXSetShapeFill(layout->bounds, gxClosedFrameFill);
  733. #endif
  734.     
  735.     /* set the initial selection to a caret before the first character */
  736.     NewSelectionAndHighlight(layout, 0, 0);
  737.         
  738.     UnlockHandle(handle);
  739.     
  740.     return handle;
  741. }
  742.  
  743. LayoutEditHandle NewLayoutEditHandle(
  744.     long textRunCount,
  745.     const short textRunLengths[],
  746.     const void *text[],
  747.     long styleRunCount,
  748.     const short styleRunLengths[],
  749.     const gxStyle styles[],
  750.     long levelRunCount,
  751.     const short levelRunLengths[],
  752.     const short levels[],
  753.     gxLayoutOptions *layoutOptions,
  754.     gxPoint *position,
  755.     gxStyle defaultStyle)
  756. {
  757.     gxShape layoutShape;
  758.     
  759.     /* just call GXNewLayout for param error checking */
  760.     layoutShape = GXNewLayout(
  761.         textRunCount,
  762.         textRunLengths,
  763.         text,
  764.         styleRunCount,
  765.         styleRunLengths,
  766.         styles,
  767.         levelRunCount,
  768.         levelRunLengths,
  769.         levels,
  770.         layoutOptions,
  771.         position);
  772.     
  773.     /* If GXNewLayout posts an error, we won't get here... */
  774.  
  775.     if (defaultStyle) GXSetShapeStyle(layoutShape, defaultStyle);
  776.     return LayoutEditHandleFromLayout(layoutShape);
  777. }
  778.  
  779. long GetLayoutEditHandle(
  780.     LayoutEditHandle handle,
  781.     void *text,
  782.     long *styleRunCount,
  783.     short styleRunLengths[],
  784.     gxStyle styles[],
  785.     long *levelRunCount,
  786.     short levelRunLengths[],
  787.     short levels[],
  788.     gxLayoutOptions *layoutOptions,
  789.     gxPoint *position)
  790. {
  791.     LayoutEditPtr layout = LockEditHandle(handle);
  792.     long result;
  793.     
  794.     UpdateLayout(layout);
  795.     
  796.     result = GXGetLayout(
  797.         layout->layout,
  798.         text,
  799.         styleRunCount,
  800.         styleRunLengths,
  801.         styles,
  802.         levelRunCount,
  803.         levelRunLengths,
  804.         levels,
  805.         layoutOptions,
  806.         position);
  807.     
  808.     UnlockHandle(handle);
  809.     
  810.     return result;
  811. }
  812.  
  813. void SetLayoutEditHandle(
  814.     LayoutEditHandle handle,
  815.     long textRunCount,
  816.     const short textRunLengths[],
  817.     const void *text[],
  818.     long styleRunCount,
  819.     const short styleRunLengths[],
  820.     const gxStyle styles[],
  821.     long levelRunCount,
  822.     const short levelRunLengths[],
  823.     const short levels[],
  824.     const gxLayoutOptions *layoutOptions,
  825.     const gxPoint *position)
  826. {
  827.     LayoutEditPtr layout = LockEditHandle(handle);
  828.     
  829.     SetEraser(layout);
  830.  
  831.     UpdateLayout(layout);
  832.     
  833.     GXSetLayout(
  834.         layout->layout,
  835.         textRunCount,
  836.         textRunLengths,
  837.         text,
  838.         styleRunCount,
  839.         styleRunLengths,
  840.         styles,
  841.         levelRunCount,
  842.         levelRunLengths,
  843.         levels,
  844.         layoutOptions,
  845.         position);
  846.     
  847.     DrawChangedLayout(layout);
  848.     
  849.     UnlockHandle(handle);
  850. }
  851.  
  852. void SetLayoutEditHandleParts(
  853.     LayoutEditHandle handle,
  854.     gxByteOffset oldStartOffset,
  855.     gxByteOffset oldEndOffset,
  856.     long newTextRunCount,
  857.     const short newTextRunLengths[],
  858.     const void *newText[],
  859.     long newStyleRunCount,
  860.     const short newStyleRunLengths[],
  861.     const gxStyle newStyles[],
  862.     long newLevelRunCount,
  863.     const short newLevelRunLengths[],
  864.     const short newLevels[])
  865. {
  866.     LayoutEditPtr layout = LockEditHandle(handle);
  867.     
  868.     SetEraser(layout);
  869.  
  870.     UpdateLayout(layout);
  871.     
  872.     GXSetLayoutParts(
  873.         layout->layout,
  874.         oldStartOffset,
  875.         oldEndOffset,
  876.         newTextRunCount,
  877.         newTextRunLengths,
  878.         newText,
  879.         newStyleRunCount,
  880.         newStyleRunLengths,
  881.         newStyles,
  882.         newLevelRunCount,
  883.         newLevelRunLengths,
  884.         newLevels);
  885.     
  886.     DrawChangedLayout(layout);
  887.     
  888.     UnlockHandle(handle);
  889. }
  890.  
  891. void SetLayoutEditHandleSelectedParts(
  892.     LayoutEditHandle handle,
  893.     long newTextRunCount,
  894.     const short newTextRunLengths[],
  895.     const void *newText[],
  896.     long newStyleRunCount,
  897.     const short newStyleRunLengths[],
  898.     const gxStyle newStyles[],
  899.     long newLevelRunCount,
  900.     const short newLevelRunLengths[],
  901.     const short newLevels[])
  902. {
  903.     LayoutEditPtr layout;
  904.     SelectionOffset startOffset, endOffset;
  905.     
  906.     layout = LockEditHandle(handle);
  907.     UpdateLayout(layout);
  908.     
  909.     DisposeStyleAt(&layout->insertionStyle);
  910.     layout->insertionLevel = -1;
  911.                     
  912.     switch (GetSelectionType(layout->selection))
  913.     {
  914.         case emptySelection:
  915.         case discontiguousRange:
  916.             /* should never happen */
  917.             break;
  918.             
  919.         case simpleCaret:
  920.             startOffset = endOffset = GetCaretSelection(layout->selection, nil);
  921.  
  922.             if (newTextRunCount == 0)
  923.             {
  924.                 if (newStyleRunCount == 1 && newStyleRunLengths[0] == 0)
  925.                 {
  926.                     layout->insertionStyle = GXCloneStyle(newStyles[0]);
  927.                     newStyleRunCount = 0;
  928.                     newStyleRunLengths = nil;
  929.                     newStyles = nil;
  930.                 }
  931.                 
  932.                 if (newLevelRunCount == 1 && newLevelRunLengths[0] == 0)
  933.                 {
  934.                     layout->insertionLevel = newLevels[0];
  935.                     newLevelRunCount = 0;
  936.                     newLevelRunLengths = nil;
  937.                     newLevels = nil;
  938.                 }
  939.             }
  940.                 
  941.             break;
  942.             
  943.         case simpleRange:
  944.         {
  945.             SelectionRanges *ranges = &layout->selectionRanges;
  946.         
  947.             (void) GetRangeSelection(layout->selection, ranges);
  948.             
  949.             startOffset = ranges->ranges[0].minOffset;
  950.             endOffset = ranges->ranges[0].maxOffset;
  951.             
  952.             break;
  953.         }
  954.     }
  955.  
  956.         
  957.     if (newTextRunCount > 0 || newStyleRunCount > 0 || newLevelRunCount > 0)
  958.     {            
  959.         SetEraser(layout);
  960.     
  961.         GXSetLayoutParts(
  962.             layout->layout,
  963.             startOffset,
  964.             endOffset,
  965.             newTextRunCount, newTextRunLengths, newText,
  966.             newStyleRunCount, newStyleRunLengths, newStyles,
  967.             newLevelRunCount, newLevelRunLengths, newLevels);
  968.  
  969.         DrawChangedLayout(layout);
  970.     }
  971.         
  972.     UnlockEditHandle(handle);
  973. }
  974.  
  975. void SetLayoutEditHandleShapeParts(
  976.     LayoutEditHandle handle,
  977.     gxByteOffset startOffset,
  978.     gxByteOffset endOffset,
  979.     gxShape insert)
  980. {
  981.     LayoutEditPtr layout = LockEditHandle(handle);
  982.     
  983.     SetEraser(layout);
  984.  
  985.     UpdateLayout(layout);
  986.     
  987.     GXSetLayoutShapeParts(
  988.         layout->layout,
  989.         startOffset,
  990.         endOffset,
  991.         insert);
  992.     
  993.     DrawChangedLayout(layout);
  994.     
  995.     UnlockHandle(handle);
  996. }
  997.  
  998. long GetLayoutEditHandleParts(
  999.     LayoutEditHandle handle,
  1000.     gxByteOffset startOffset,
  1001.     gxByteOffset endOffset,
  1002.     void *text,
  1003.     long *styleRunCount,
  1004.     short styleRunLengths[],
  1005.     gxStyle styles[],
  1006.     long *levelRunCount,
  1007.     short levelRunLengths[],
  1008.     short levels[])
  1009. {
  1010.     LayoutEditPtr layout = LockEditHandle(handle);
  1011.     long result;
  1012.     
  1013.     UpdateLayout(layout);
  1014.     
  1015.     result = GXGetLayoutParts(
  1016.         layout->layout,
  1017.         startOffset,
  1018.         endOffset,
  1019.         text,
  1020.         styleRunCount,
  1021.         styleRunLengths,
  1022.         styles,
  1023.         levelRunCount,
  1024.         levelRunLengths,
  1025.         levels);
  1026.     
  1027.     UnlockHandle(handle);
  1028.     return result;
  1029. }
  1030.  
  1031. long GetLayoutEditHandleSelectedParts(
  1032.     LayoutEditHandle handle,
  1033.     void *text,
  1034.     long *styleRunCount,
  1035.     short styleRunLengths[],
  1036.     gxStyle styles[],
  1037.     long *levelRunCount,
  1038.     short levelRunLengths[],
  1039.     short levels[])
  1040. {
  1041.     SelectionType selectionType;
  1042.     gxByteOffset endOffset, startOffset;
  1043.     LayoutEditPtr layout;
  1044.     long result;
  1045.     
  1046.     layout = LockEditHandle(handle);
  1047.     UpdateLayout(layout);
  1048.     selectionType = GetSelectionType(layout->selection);
  1049.     
  1050.     switch (selectionType)
  1051.     {
  1052.     case emptySelection:
  1053.     case discontiguousRange:
  1054.         /* should never happen */
  1055.         break;
  1056.         
  1057.     case simpleCaret:
  1058.     
  1059.         startOffset = endOffset = GetCaretSelection(layout->selection, nil);
  1060.  
  1061.         if (styles != nil && layout->insertionStyle != nil)
  1062.         {
  1063.             *styles = layout->insertionStyle;
  1064.             styles = nil;
  1065.         }
  1066.         
  1067.         if (levels != nil && layout->insertionLevel >= 0)
  1068.         {
  1069.             *levels = layout->insertionLevel;
  1070.             levels = nil;
  1071.         }
  1072.  
  1073.         break;
  1074.         
  1075.     case simpleRange:
  1076.     {
  1077.         SelectionRanges *ranges = &layout->selectionRanges;
  1078. //        short length;
  1079.                 
  1080.         (void) GetRangeSelection(layout->selection, ranges);
  1081.         
  1082.         startOffset = ranges->ranges[0].minOffset;
  1083.         endOffset = ranges->ranges[0].maxOffset;
  1084.     }
  1085.  
  1086.     }
  1087.             
  1088.     result = GXGetLayoutParts(
  1089.         layout->layout,
  1090.         startOffset,
  1091.         endOffset,
  1092.         text,
  1093.         styleRunCount,
  1094.         styleRunLengths,
  1095.         styles,
  1096.         levelRunCount,
  1097.         levelRunLengths,
  1098.         levels);
  1099.     
  1100.     UnlockHandle(handle);
  1101.     return result;
  1102. }
  1103.  
  1104. gxShape GetLayoutEditHandleShapeParts(
  1105.     LayoutEditHandle handle,
  1106.     gxByteOffset startOffset,
  1107.     gxByteOffset endOffset,
  1108.     gxShape dest)
  1109. {
  1110.     LayoutEditPtr layout = LockEditHandle(handle);
  1111.     gxShape result;
  1112.     
  1113.     UpdateLayout(layout);
  1114.     
  1115.     result = GXGetLayoutShapeParts(layout->layout, startOffset, endOffset, dest);
  1116.     
  1117.     UnlockHandle(handle);
  1118.     return result;
  1119. }
  1120.  
  1121. void LayoutEditRotateShape(LayoutEditHandle handle, Fixed degrees, Fixed translateX, Fixed translateY)
  1122. {
  1123.     LayoutEditPtr layout;
  1124.     
  1125.     layout = LockEditHandle(handle);
  1126.     
  1127.     UpdateLayout(layout);
  1128.  
  1129.     SetEraser(layout);
  1130.     
  1131.     GXRotateShape(layout->layout, degrees, translateX, translateY);
  1132.     
  1133.     DrawChangedLayout(layout);
  1134.     
  1135.     UnlockEditHandle(handle);
  1136. }
  1137.  
  1138. void LayoutEditIdle(LayoutEditHandle handle)
  1139. {
  1140.     ulong ticks = TickCount();
  1141.     ulong nextUpdateTime = ((LayoutEditPtr) *handle)->nextUpdateTime;
  1142.     ulong nextBlinkTime = ((LayoutEditPtr) *handle)->nextBlinkTime;
  1143.     
  1144.     if ((nextUpdateTime != 0) && (ticks >= nextUpdateTime))
  1145.     {
  1146.         LayoutEditPtr layout = LockEditHandle(handle);
  1147.         
  1148.         HideHighlight(layout);
  1149.         UpdateLayout(layout);
  1150.         ShowHighlight(layout);
  1151.         
  1152.         UnlockEditHandle(handle);
  1153.     }
  1154.  
  1155.     if (((LayoutEditPtr) *handle)->flags & highlightBlinks)
  1156.     {
  1157.         if (ticks >= nextBlinkTime)
  1158.         {
  1159.             LayoutEditPtr layout = LockEditHandle(handle);
  1160.  
  1161.             if (layout->flags & highlightIsBlinking)
  1162.             {
  1163.                 UpdateLayout(layout);
  1164.                 ShowHighlight(layout);
  1165.             }
  1166.             else
  1167.             {
  1168.                 HideHighlight(layout);
  1169.             }
  1170.             
  1171.             layout->flags ^= highlightIsBlinking;
  1172.  
  1173.             layout->nextBlinkTime = ticks + GetCaretTime();
  1174.  
  1175.             UnlockEditHandle(handle);
  1176.         }
  1177.     }
  1178. }
  1179.  
  1180. void LayoutEditClick(LayoutEditHandle handle, gxPoint hitDown, Boolean extend)
  1181. {
  1182.     LayoutEditPtr layout = LockEditHandle(handle); 
  1183.     gxPoint lastPoint = hitDown;
  1184.     SelectionOffset firstHitOffset, lastHitOffset;
  1185.     gxLayoutHitInfo hitInfo;
  1186.     Boolean oldIsCaret, newIsCaret = true;
  1187.     gxShape diffHighlight = nil, oldHighlight = nil;
  1188.     gxViewPort layoutViewPort = GetShapeViewPort(layout->layout);
  1189.  
  1190.     /* get the offset for the hit down gxPoint */
  1191.     GXHitTestLayout(layout->layout, &hitDown, gxHighlightAverageAngle, &hitInfo, nil);
  1192.  
  1193.     if (extend)
  1194.     {
  1195.         Boolean extendLeft;
  1196.         SelectionOffset oldFirstOffset, oldLastOffset;
  1197.         
  1198.         switch (GetSelectionType(layout->selection))
  1199.         {
  1200.         case emptySelection:
  1201.         case discontiguousRange:
  1202.             oldFirstOffset = oldLastOffset = (SelectionOffset) hitInfo.hitSideOffset;
  1203.             break;
  1204.             
  1205.         case simpleCaret:
  1206.             oldFirstOffset = oldLastOffset = GetCaretSelection(layout->selection, nil);
  1207.             break;
  1208.         
  1209.         case simpleRange:
  1210.         {
  1211.             SelectionRanges *ranges = &layout->selectionRanges;
  1212.         
  1213.             (void) GetRangeSelection(layout->selection, ranges);
  1214.             oldFirstOffset = ranges->ranges[0].minOffset;
  1215.             oldLastOffset = ranges->ranges[0].maxOffset;
  1216.             break;
  1217.         }
  1218.         }
  1219.  
  1220.         if (hitInfo.hitSideOffset <= oldFirstOffset)
  1221.             extendLeft = true;
  1222.         else if (hitInfo.hitSideOffset >= oldLastOffset)
  1223.             extendLeft = false;
  1224.         else
  1225.             extendLeft = ((hitInfo.hitSideOffset - oldFirstOffset) <= (oldLastOffset - hitInfo.hitSideOffset));
  1226.  
  1227.         if (extendLeft)
  1228.         {
  1229.             firstHitOffset = (SelectionOffset) hitInfo.hitSideOffset;
  1230.             lastHitOffset = oldLastOffset;
  1231.         }
  1232.         else
  1233.         {
  1234.             firstHitOffset = oldFirstOffset;
  1235.             lastHitOffset = (SelectionOffset) hitInfo.hitSideOffset;
  1236.         }
  1237.     }
  1238.     else
  1239.         firstHitOffset = lastHitOffset = (SelectionOffset) hitInfo.hitSideOffset;
  1240.     
  1241.     /* erase the old highlight */
  1242.     ResetCaret(layout);
  1243.     DrawHighlight(layout);
  1244.  
  1245.     /* recompute the selection and highlight while the mouse button is still down */
  1246.     while (Button())
  1247.     {
  1248.         GXGetViewPortMouse(layoutViewPort, &hitDown);
  1249.     
  1250.         /* continue if the mouse hasn't moved */
  1251.         if (hitDown.x == lastPoint.x && hitDown.y == lastPoint.y)
  1252.             continue;
  1253.         
  1254.         lastPoint = hitDown;
  1255.         GXHitTestLayout(layout->layout, &hitDown, gxHighlightAverageAngle, &hitInfo, nil);
  1256.         
  1257.         /* continue if the selection hasn't changed */
  1258.         if (hitInfo.hitSideOffset == lastHitOffset) continue;
  1259.         
  1260.         oldIsCaret = newIsCaret;
  1261.  
  1262.         /* save the old highlight and calculate the new one */
  1263.         lastHitOffset = (SelectionOffset) hitInfo.hitSideOffset;
  1264.         newIsCaret = (lastHitOffset == firstHitOffset);
  1265.         
  1266.         if (oldIsCaret || newIsCaret)
  1267.         {
  1268.             if (!oldIsCaret)
  1269.                 DrawHighlight(layout);
  1270.             if (!newIsCaret)
  1271.             {
  1272.                 NewSelectionAndHighlight(layout, firstHitOffset, lastHitOffset);
  1273.                 DrawHighlight(layout);
  1274.             }
  1275.         }
  1276.         else
  1277.         {
  1278.             oldHighlight = GXCopyToShape(oldHighlight, layout->highlight);
  1279.             NewSelectionAndHighlight(layout, firstHitOffset, lastHitOffset);
  1280.         
  1281.             /* to reduce flicker, draw the difference between the new and old highlight */
  1282.             diffHighlight = GXCopyToShape(diffHighlight, layout->highlight);
  1283.             GXExcludeShape(diffHighlight, oldHighlight);
  1284.             if (layout->highlightHideCount <= 0)
  1285.                 GXDrawShape(diffHighlight);
  1286.         }
  1287.     }
  1288.  
  1289.     if (newIsCaret)
  1290.     {
  1291.         ResetCaret(layout);
  1292.         NewSelectionAndHighlight(layout, firstHitOffset, lastHitOffset);
  1293.         DrawHighlight(layout);
  1294.     }
  1295.  
  1296.     UnlockEditHandle(handle);
  1297.  
  1298.     DisposeShapeAt(&diffHighlight);
  1299.     DisposeShapeAt(&oldHighlight);
  1300. }
  1301.  
  1302.  
  1303. void LayoutEditActivate(LayoutEditHandle handle)
  1304. {
  1305.     LayoutEditPtr layout = LockEditHandle(handle);
  1306.  
  1307.     if (layout->oldScript != GetScriptManagerVariable(smKeyScript))
  1308.         KeyScript(layout->oldScript);
  1309.         
  1310.     UpdateLayout(layout);
  1311.     ShowHighlight(layout);
  1312.     UnlockEditHandle(handle);
  1313. }
  1314.  
  1315.  
  1316. void LayoutEditDeactivate(LayoutEditHandle handle)
  1317. {
  1318.     LayoutEditPtr layout = LockEditHandle(handle);
  1319.  
  1320.     layout->oldScript = GetScriptManagerVariable(smKeyScript);
  1321.     
  1322.     HideHighlight(layout);
  1323.     UnlockEditHandle(handle);
  1324. }
  1325.  
  1326.  
  1327. void LayoutEditKey(LayoutEditHandle handle, char key)
  1328. {
  1329.     LayoutEditPtr layout = LockEditHandle(handle);
  1330.  
  1331.     switch (key)
  1332.     {
  1333.     case leftArrow:
  1334.     case rightArrow:
  1335.     {
  1336.         SelectionOffset newCaret; 
  1337.         
  1338.         HideHighlight(layout);
  1339.         UpdateLayout(layout);
  1340.         
  1341.         if (key == leftArrow)
  1342.             newCaret = GXGetLeftVisualOffset(
  1343.                 layout->layout,
  1344.                 layout->selectionRanges.ranges[0].minOffset);
  1345.         else newCaret = GXGetRightVisualOffset(
  1346.             layout->layout,
  1347.             layout->selectionRanges.ranges[0].maxOffset);
  1348.         
  1349.         NewSelection(layout, newCaret, newCaret);
  1350.         ResetCaret(layout);
  1351.         ShowHighlight(layout);
  1352.         break;
  1353.     }
  1354.     
  1355.     case backSpace:
  1356.     {
  1357.         DeleteSelection(layout);
  1358.         if (layout->nextUpdateTime == 0)
  1359.             layout->nextUpdateTime = TickCount() + nextUpdateDelta;
  1360.         break;
  1361.     }
  1362.     
  1363.     default:
  1364.     {    
  1365.     
  1366.         switch (GetSelectionType(layout->selection))
  1367.         {
  1368.         case emptySelection:
  1369.             break;
  1370.         
  1371.         case discontiguousRange:
  1372.         case simpleRange:
  1373.             DeleteSelection(layout);
  1374.         
  1375.             /* fall through to simpleCaret case */
  1376.         
  1377.         case simpleCaret:
  1378.             InsertByte(layout, key);
  1379.             if (layout->nextUpdateTime == 0)
  1380.                 layout->nextUpdateTime = TickCount() + nextUpdateDelta;
  1381.         }
  1382.     }
  1383.     }
  1384.     
  1385.     UnlockEditHandle(handle);
  1386. }
  1387.  
  1388.  
  1389. void LayoutEditUpdate(LayoutEditHandle handle)
  1390. {
  1391.     LayoutEditPtr layout = LockEditHandle(handle);
  1392.  
  1393.     GXDrawShape(layout->layout);
  1394.  
  1395. #if BOUNDS    
  1396.     GXDrawShape(layout->bounds);
  1397. #endif
  1398.  
  1399.     DrawHighlight(layout);
  1400.     
  1401.     UnlockEditHandle(handle);
  1402. }
  1403.  
  1404.  
  1405. SelectionHandle LayoutEditGetSelection(LayoutEditHandle handle)
  1406. {
  1407.   LayoutEditPtr layout = (LayoutEditPtr) LockHandle(handle);
  1408.    SelectionHandle selection;
  1409.  
  1410.    UpdateLayout(layout);
  1411.    selection = layout->selection;
  1412.    UnlockEditHandle(handle);
  1413.  
  1414.    return selection;
  1415. }
  1416.  
  1417. void LayoutEditSetSelection(LayoutEditHandle handle, SelectionOffset start, SelectionOffset end)
  1418. {
  1419.     LayoutEditPtr layout = LockEditHandle(handle);
  1420.  
  1421.     UpdateLayout(layout);
  1422.     
  1423.     HideHighlight(layout);
  1424.     NewSelection(layout, start, end);
  1425.     ShowHighlight(layout);
  1426.     
  1427.     UnlockEditHandle(handle);
  1428. }
  1429.  
  1430. void LayoutEditSetSelectionHandle(LayoutEditHandle handle, SelectionHandle selection)
  1431. {
  1432.     SelectionOffset end, start;
  1433.  
  1434.     switch (GetSelectionType(selection))
  1435.     {
  1436.     case emptySelection:
  1437.     case discontiguousRange:
  1438.         return;
  1439.         
  1440.     case simpleCaret:
  1441.         start = end = GetCaretSelection(selection, nil);
  1442.         break;
  1443.     
  1444.     case simpleRange:
  1445.     {
  1446.         SelectionRanges ranges;
  1447.     
  1448.         (void) GetRangeSelection(selection, &ranges);
  1449.         start = ranges.ranges[0].minOffset;
  1450.         end = ranges.ranges[0].maxOffset;
  1451.         break;
  1452.     }
  1453.  
  1454.     }
  1455.     
  1456.     LayoutEditSetSelection(handle, start, end);
  1457. }
  1458.  
  1459. gxViewPort GetLayoutEditViewPort(LayoutEditHandle handle)
  1460. {
  1461.     LayoutEditPtr layout = LockEditHandle(handle);
  1462.     gxViewPort viewPort = GetShapeViewPort(layout->layout);
  1463.     
  1464.     UnlockEditHandle(handle);
  1465.     return viewPort;
  1466. }
  1467.  
  1468. void LayoutEditSetStyle(LayoutEditHandle handle, gxStyle newStyle)
  1469. {
  1470.     LayoutEditPtr layout = LockEditHandle(handle);
  1471.     SelectionType selectionType = GetSelectionType(layout->selection);
  1472.     
  1473.     UpdateLayout(layout);
  1474.     
  1475.     DisposeStyleAt(&layout->insertionStyle);
  1476.                     
  1477.     switch (selectionType)
  1478.     {
  1479.     case emptySelection:
  1480.     case discontiguousRange:
  1481.         /* should never happen */
  1482.         break;
  1483.         
  1484.     case simpleCaret:
  1485.         layout->insertionStyle = GXCloneStyle(newStyle);
  1486.         break;
  1487.         
  1488.     case simpleRange:
  1489.     {
  1490.         SelectionRanges *ranges = &layout->selectionRanges;
  1491.         SelectionOffset startOffset, endOffset;
  1492.         short length;
  1493.     
  1494.         SetEraser(layout);
  1495.         
  1496.         (void) GetRangeSelection(layout->selection, ranges);
  1497.         
  1498.         startOffset = ranges->ranges[0].minOffset;
  1499.         endOffset = ranges->ranges[0].maxOffset;
  1500.         length = endOffset - startOffset;
  1501.         
  1502.         GXSetLayoutParts(
  1503.             layout->layout,
  1504.             startOffset,
  1505.             endOffset,
  1506.             0,
  1507.             nil,
  1508.             nil,
  1509.             1,
  1510.             &length,
  1511.             &newStyle,
  1512.             0,
  1513.             nil,
  1514.             nil);
  1515.             
  1516.         DrawChangedLayout(layout);
  1517.  
  1518.         break;
  1519.     }
  1520.     }
  1521.  
  1522.     UnlockEditHandle(handle);
  1523. }
  1524.  
  1525. void LayoutEditIncrementLevel(LayoutEditHandle handle)
  1526. {
  1527.     LayoutEditPtr layout = LockEditHandle(handle);
  1528.  
  1529.     HideHighlight(layout);
  1530.     AdjustSelectedLevels(layout, 1);
  1531.     layout->flags |= highlightOutOfDate;
  1532.     ShowHighlight(layout);
  1533.     
  1534.     UnlockEditHandle(handle);
  1535. }
  1536.  
  1537. void LayoutEditDecrementLevel(LayoutEditHandle handle)
  1538. {
  1539.     LayoutEditPtr layout = LockEditHandle(handle);
  1540.  
  1541.     HideHighlight(layout);
  1542.     AdjustSelectedLevels(layout, -1);
  1543.     layout->flags |= highlightOutOfDate;
  1544.     ShowHighlight(layout);
  1545.     
  1546.     UnlockEditHandle(handle);
  1547. }
  1548.  
  1549. void LayoutEditSetLevel(LayoutEditHandle handle, long level)
  1550. {
  1551.     LayoutEditPtr layout = LockEditHandle(handle);
  1552.     SelectionType selectionType = GetSelectionType(layout->selection);
  1553.     short newLevel = level;
  1554.     
  1555.     UpdateLayout(layout);
  1556.     
  1557.     switch (selectionType)
  1558.     {
  1559.     case emptySelection:
  1560.     case discontiguousRange:
  1561.         /* should never happen */
  1562.         break;
  1563.         
  1564.     case simpleCaret:
  1565.         layout->insertionLevel = newLevel;
  1566.         break;
  1567.         
  1568.     case simpleRange:
  1569.     {
  1570.         SelectionRanges *ranges = &layout->selectionRanges;
  1571.         SelectionOffset startOffset, endOffset;
  1572.         short length;
  1573.     
  1574.         SetEraser(layout);
  1575.         
  1576.         (void) GetRangeSelection(layout->selection, ranges);
  1577.         
  1578.         startOffset = ranges->ranges[0].minOffset;
  1579.         endOffset = ranges->ranges[0].maxOffset;
  1580.         length = endOffset - startOffset;
  1581.         
  1582.         GXSetLayoutParts(
  1583.             layout->layout,
  1584.             startOffset,
  1585.             endOffset,
  1586.             0,
  1587.             nil,
  1588.             nil,
  1589.             0,
  1590.             nil,
  1591.             nil,
  1592.             1,
  1593.             &length,
  1594.             &newLevel);
  1595.             
  1596. #if BOUNDS            
  1597.         SetBounds(layout);
  1598. #endif
  1599.  
  1600.         HideHighlight(layout);
  1601.         DrawDifference(layout);
  1602.         layout->flags |= highlightOutOfDate;
  1603.         ShowHighlight(layout);
  1604.         
  1605.         layout->insertionLevel = -1;
  1606.         break;
  1607.     }
  1608.     
  1609.     }
  1610.  
  1611.     UnlockEditHandle(handle);
  1612. }
  1613.  
  1614. void LayoutEditCut(LayoutEditHandle handle)
  1615. {
  1616.     LayoutEditPtr layout = LockEditHandle(handle);
  1617.     SelectionType selectionType = GetSelectionType(layout->selection);
  1618.  
  1619.     if (selectionType != emptySelection && selectionType != simpleCaret)
  1620.     {
  1621.         CopySelection(layout);
  1622.         DeleteSelection(layout);
  1623.         HideHighlight(layout);
  1624.         UpdateLayout(layout);
  1625.         ShowHighlight(layout);
  1626.     }
  1627.     
  1628.     UnlockEditHandle(handle);
  1629. }
  1630.  
  1631. void LayoutEditCopy(LayoutEditHandle handle)
  1632. {
  1633.     LayoutEditPtr layout = LockEditHandle(handle);
  1634.  
  1635.     CopySelection(layout);
  1636.     
  1637.     UnlockEditHandle(handle);
  1638. }
  1639.  
  1640. void LayoutEditPaste(LayoutEditHandle handle)
  1641. {
  1642.     LayoutEditPtr layout = LockEditHandle(handle);
  1643.  
  1644.     HideHighlight(layout);
  1645.     PasteSelection(layout);
  1646.     ShowHighlight(layout);
  1647.     
  1648.     UnlockEditHandle(handle);
  1649. }
  1650.  
  1651. void LayoutEditClear(LayoutEditHandle handle)
  1652. {
  1653.     LayoutEditPtr layout = LockEditHandle(handle);
  1654.  
  1655.     DeleteSelection(layout);
  1656.     HideHighlight(layout);
  1657.     UpdateLayout(layout);
  1658.     ShowHighlight(layout);
  1659.     
  1660.     UnlockEditHandle(handle);
  1661. }
  1662.  
  1663. void LayoutEditFromScrap(LayoutEditHandle handle)
  1664. {
  1665.     LayoutEditPtr layout = LockEditHandle(handle);
  1666.     long offset, length;
  1667.     Handle buffer = NewHandle(0);
  1668.     
  1669.     if (GetScrap(buffer, 'FLAY', &offset) > 0)
  1670.     {
  1671.         long portCount = GXGetShapeViewPorts(GXGetDefaultShape(gxLayoutType), nil);
  1672.         gxViewPort *ports = (gxViewPort *) NewPtr(portCount * sizeof(gxViewPort));
  1673.     
  1674.         GXGetShapeViewPorts(GXGetDefaultShape(gxLayoutType), ports);
  1675.         DisposeShapeAt(&layout->scrap);
  1676.     
  1677.         layout->scrap = HandleToShape(buffer, portCount, ports);
  1678.         DisposePtr((Ptr) ports);
  1679.     }
  1680.     else if ((length = GetScrap(buffer, 'TEXT', &offset)) > 0)
  1681.     {
  1682.         void *text = (void *) LockHandle(buffer);
  1683.         short runLength = length;
  1684.         gxStyle defaultStyle = GXGetShapeStyle(layout->layout);
  1685.         short level0 = 0;
  1686.         
  1687.         DisposeShapeAt(&layout->scrap);
  1688.         layout->scrap = GXNewLayout(
  1689.             1,
  1690.             &runLength,
  1691.             (const void **) &text,
  1692.             1,
  1693.             &runLength,
  1694.             &defaultStyle,
  1695.             1,
  1696.             &runLength,
  1697.             &level0,
  1698.             nil,
  1699.             nil);
  1700.         
  1701.     }
  1702.     
  1703.     DisposeHandle(buffer);
  1704.     
  1705.     UnlockEditHandle(handle);
  1706. }
  1707.  
  1708. void LayoutEditToScrap(LayoutEditHandle handle)
  1709. {
  1710.     LayoutEditPtr layout = LockEditHandle(handle);
  1711.     
  1712.     ZeroScrap();
  1713.     
  1714.     if (layout->scrap)
  1715.     {
  1716.         long textLength;
  1717.         Ptr textPtr;
  1718.         Handle shapeHandle = ShapeToHandle(layout->scrap);
  1719.         
  1720.     
  1721.         textLength = GXGetLayout(layout->scrap, nil, nil, nil, nil, nil, nil, nil, nil, nil);
  1722.         textPtr = NewPtr(textLength);
  1723.         GXGetLayout(layout->scrap, (void *) textPtr, nil, nil, nil, nil, nil, nil, nil, nil);
  1724.         
  1725.         PutScrap(GetHandleSize(shapeHandle), 'FLAY', LockHandle(shapeHandle));
  1726.         PutScrap(textLength, 'TEXT', textPtr);
  1727.         
  1728.         DisposeShapeAt(&layout->scrap);
  1729.         DisposePtr(textPtr);
  1730.         DisposeHandle(shapeHandle);
  1731.     }
  1732.     
  1733.     UnlockEditHandle(handle);
  1734. }
  1735.  
  1736.  
  1737. void DisposeLayoutEditHandle(LayoutEditHandle handle)
  1738. {
  1739.     LayoutEditPtr layout = (LayoutEditPtr) LockHandle(handle);
  1740.  
  1741. #if BOUNDS
  1742.     DisposeShapeAt(&layout->bounds);
  1743.     DisposeShapeAt(&layout->boundsEraser);
  1744. #endif
  1745.  
  1746.     DisposeShapeAt(&layout->layout);
  1747.     DisposeShapeAt(&layout->eraser);
  1748.     DisposeShapeAt(&layout->highlight);
  1749.     DisposeShapeAt(&layout->scrap);
  1750.     DisposeStyleAt(&layout->insertionStyle);
  1751.     DisposeSelection(layout->selection);
  1752.     DisposeHandle(handle);
  1753. }
  1754.